package com.xxx.car.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.xxx.car.constants.ChargeDetailType;
import com.xxx.car.constants.PayOrderStatus;
import com.xxx.car.constants.PayOrderType;
import com.xxx.car.entity.*;
import com.xxx.car.entity.vo.request.*;
import com.xxx.car.entity.vo.response.*;
import com.xxx.car.mapper.ITbMapper;
import com.xxx.car.mapper.TbChargeDetailMapper;
import com.xxx.car.mapper.TbChargeGiveMapper;
import com.xxx.car.mapper.TbPayOrderMapper;
import com.xxx.car.service.TradeService;
import com.xxx.car.service.UserWalletService;
import com.xxx.common.base.exception.BizException;
import com.xxx.common.pay.core.Pay;
import com.xxx.common.pay.core.vo.ExtParam;
import com.xxx.common.pay.core.vo.RequestResult;
import com.xxx.common.pay.service.PayService;
import com.xxx.common.util.IdWorker;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Created by xuwenjie on 2017/6/16.
 */
@Service
public class TradeServiceImpl implements TradeService {

    @Autowired
    private TbPayOrderMapper tbPayOrderMapper;

    @Autowired
    private TbChargeGiveMapper tbChargeGiveMapper;

    @Autowired
    private TbChargeDetailMapper tbChargeDetailMapper;

    @Autowired
    private ITbMapper iTbMapper;

    @Autowired
    private UserWalletService userWalletService;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private PayService payService;

    @Value("${pay.baseCallbackUrl}")
    private String callBackUrl;


    public Map<String, String> createPayOrder(String orderId, ReqChargeCreateOrder chargeCreateOrder) {
        TbPayOrder order = new TbPayOrder();
        order.setOrderId(orderId);
        order.setUserId(chargeCreateOrder.getUserId());
        order.setAmt(chargeCreateOrder.getAmt());
        order.setType(PayOrderType.CHARGE);
        order.setStatus(PayOrderStatus.CREATE);
        order.setPayChannel(chargeCreateOrder.getPayChannel());
        order.setRemark(chargeCreateOrder.getRemark());
        order.setCreateTime(new Date());
        order.setUpdateTime(new Date());
        tbPayOrderMapper.insert(order);

        ExtParam ext = new ExtParam();
        ext.setNotifyUrl(callBackUrl + chargeCreateOrder.getPayChannel());
        ext.setUserIp(chargeCreateOrder.getUserIp());

        RequestResult requestResult = payService.pay(chargeCreateOrder.getPayChannel(), Pay.PLATFORM_APP, order.getOrderId(), order.getAmt(), order.getRemark(), ext);
        return requestResult.getMap();
    }

    @Override
    public Map<String, String> createPayOrder(ReqChargeCreateOrder chargeCreateOrder) {
        return createPayOrder(String.valueOf(idWorker.nextId()), chargeCreateOrder);
    }

    @Override
    public List<RespChargeGive> getAllChargeGive() {
        return tbChargeGiveMapper.findAll().stream().map(e -> {
            RespChargeGive respChargeGive = new RespChargeGive();
            BeanUtils.copyProperties(e, respChargeGive);
            return respChargeGive;
        }).collect(Collectors.toList());
    }

    @Override
    public void delteChargeGive(Integer id) {
        tbChargeGiveMapper.deleteByPrimaryKey(id);
    }

    @Override
    @Transactional
    public void finishPay(String orderId, String transactionId, Long amt) {
        TbPayOrder order = tbPayOrderMapper.selectByPrimaryKeyForUpdate(orderId);
        if (order == null) {
            throw new BizException("订单不存在");
        }
        if (order.getStatus() == PayOrderStatus.SUCCESS) {
            return;
        }
        if (order.getStatus() != PayOrderStatus.CREATE) {
            throw new BizException("订单状态异常");
        }
        if (!order.getAmt().equals(amt)) {
            throw new BizException("订单金额异常");
        }

        if (order.getType() == PayOrderType.CHARGE) {
            TbChargeGive chargeGive = tbChargeGiveMapper.selectByChargeAmt(order.getAmt());
            Long giveAmt = 0L;
            if (chargeGive != null) {
                giveAmt = chargeGive.getGiveAmt();
            }
            //变更金额
            userWalletService.changeAmt(order.getUserId(), order.getAmt(), BigDecimal.ZERO, giveAmt, 0L);

            //充值明细

            Date now = new Date();

            TbChargeDetail detail = new TbChargeDetail();
            detail.setUserId(order.getUserId());
            detail.setAmt(order.getAmt());
            detail.setType(ChargeDetailType.PAY);
            detail.setPayChannel(order.getPayChannel());
            detail.setOrderId(orderId);
            detail.setTransactionId(transactionId);
            detail.setCreateTime(now);
            tbChargeDetailMapper.insert(detail);

            if(giveAmt > 0) {
                TbChargeDetail giveDetail = new TbChargeDetail();
                giveDetail.setUserId(order.getUserId());
                giveDetail.setAmt(giveAmt);
                giveDetail.setType(ChargeDetailType.PAY_GIVE);
                giveDetail.setOrderId(orderId);
                giveDetail.setCreateTime(now);
                tbChargeDetailMapper.insert(giveDetail);
            }
        }

        order.setTransactionId(transactionId);
        order.setStatus(PayOrderStatus.SUCCESS);
        order.setUpdateTime(new Date());
        tbPayOrderMapper.updateByPrimaryKeySelective(order);
    }

    @Override
    public List<RespChargeDetail> findChargeDetail(ReqChargeDetailQuery reqChargeDetailQuery) {
        PageHelper.startPage(reqChargeDetailQuery.getPageNum(), reqChargeDetailQuery.getPageSize());
        return tbChargeDetailMapper.query(reqChargeDetailQuery).stream().map(e -> {
            RespChargeDetail respChargeDetail = new RespChargeDetail();
            BeanUtils.copyProperties(e, respChargeDetail);
            return  respChargeDetail;
        }).collect(Collectors.toList());
    }

    @Override
    public void saveOrUpdateChargeGive(ReqChargeGiveAdmin reqChargeGiveAdmin) {
        TbChargeGive tbChargeGive = new TbChargeGive();
        BeanUtils.copyProperties(reqChargeGiveAdmin, tbChargeGive);
        if (tbChargeGive.getId() != null) {
            tbChargeGive.setUpdateTime(new Date());
            tbChargeGiveMapper.updateByPrimaryKeySelective(tbChargeGive);
        } else {
            Date now = new Date();
            tbChargeGive.setCreateTime(now);
            tbChargeGive.setUpdateTime(now);
            tbChargeGiveMapper.insert(tbChargeGive);
        }
    }

    @Override
    public RespChargeTotalStatistics chargeTotalStatistics(ReqChargeTotalStatistics reqChargeTotalStatistics) {
        TbChargeStatistics statistics = tbChargeDetailMapper.totalStatistics(reqChargeTotalStatistics);
        RespChargeTotalStatistics chargeStatistics = new RespChargeTotalStatistics();
        BeanUtils.copyProperties(statistics, chargeStatistics);
        return chargeStatistics;
    }

    @Override
    public Page<RespChargeUserStatistics> chargeUserStatistics(ReqChargeUserStatistics reqChargeUserStatistics) {
        PageHelper.startPage(reqChargeUserStatistics.getPageNum(), reqChargeUserStatistics.getPageSize());
        Page<Integer> ids = (Page<Integer>) tbChargeDetailMapper.findChargedUserId(reqChargeUserStatistics);
        if (ids != null && !ids.isEmpty()) {
            List<TbUser> users = iTbMapper.findUserByIds(ids);
            List<TbChargeUserStatistics> tbChargeUserStatisticsList = tbChargeDetailMapper.userStatistics(ids);

            List<RespChargeUserStatistics> list = tbChargeUserStatisticsList.stream().map(e -> {
                RespChargeUserStatistics respChargeUserStatistics = new RespChargeUserStatistics();
                BeanUtils.copyProperties(e, respChargeUserStatistics);
                users.stream().filter(u->u.getId().equals(e.getUserId())).findFirst().ifPresent(k->respChargeUserStatistics.setMobile(k.getMobile()));
                return respChargeUserStatistics;
            }).collect(Collectors.toList());

            Page<RespChargeUserStatistics> page = new Page<>(reqChargeUserStatistics.getPageNum(), reqChargeUserStatistics.getPageSize());
            page.setTotal(ids.getTotal());
            page.addAll(list);

            return page;
        } else {
            return new Page<>(reqChargeUserStatistics.getPageNum(), reqChargeUserStatistics.getPageSize());
        }
    }

    @Override
    public Page<RespChargeGiveDetail> findChargeDetail(ReqChargeDetailQueryForAdmin reqChargeDetailQueryForAdmin) {
        PageHelper.startPage(reqChargeDetailQueryForAdmin.getPageNum(), reqChargeDetailQueryForAdmin.getPageSize());
        Page<TbChargeDetail> chargeDetails = (Page<TbChargeDetail>) tbChargeDetailMapper.findChargeOrder(reqChargeDetailQueryForAdmin);
        if (!chargeDetails.isEmpty()) {
            List<String> orderIds = chargeDetails.stream().map(e -> e.getOrderId()).collect(Collectors.toList());
            List<TbChargeDetail> giveDetails = tbChargeDetailMapper.findByOrderIds(orderIds);

            List<RespChargeGiveDetail> list = chargeDetails.stream().map(e->{
                RespChargeGiveDetail respChargeGiveDetail = new RespChargeGiveDetail();
                respChargeGiveDetail.setOrderId(e.getOrderId());
                respChargeGiveDetail.setChargeAmt(e.getAmt());
                respChargeGiveDetail.setPayChannel(e.getPayChannel());
                respChargeGiveDetail.setChargeDate(e.getCreateTime());

                giveDetails.stream().filter(k->k.getOrderId().equals(e.getOrderId()) && k.getType().equals(ChargeDetailType.PAY_GIVE)).findFirst().ifPresent(m->respChargeGiveDetail.setGiveAmt(m.getAmt()));

                return respChargeGiveDetail;
            }).collect(Collectors.toList());

            Page<RespChargeGiveDetail> page = new Page<>(reqChargeDetailQueryForAdmin.getPageNum(), reqChargeDetailQueryForAdmin.getPageSize());
            page.setTotal(chargeDetails.getTotal());
            page.addAll(list);

            return page;
        } else {
            return new Page<>(reqChargeDetailQueryForAdmin.getPageNum(), reqChargeDetailQueryForAdmin.getPageSize());
        }
    }

}
